// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The main function for a Go program.

#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#include <async.h>
#include <fibril.h>

#include "runtime_types.h"
#include "mem_alloc.h"
#include "proc.h"
#include "string.h"


extern Slice os_Args asm ("os.Args");

// TODO: Put this in package os.
static void
runtime_goargs(int32 argc, byte **argv)
{
	String *s;
	int32 i;

	s = runtime_malloc(argc*sizeof s[0]);
	for(i=0; i<argc; i++)
		s[i] = runtime_gostringnocopy((const byte*)argv[i]);
	os_Args.__values = (void*)s;
	os_Args.__count = argc;
	os_Args.__capacity = argc;
}

// The main function for a Go program.  This records the command line
// parameters, calls the real main function, and returns a zero status
// if the real main function returns.

static void mainstart(void *);

// The program entry point.
int main(int argc, char **argv)
{
	runtime_fibril_setup();
	//runtime_check();

	//runtime_memprof_disable();
	runtime_mallocinit();

	// Must be called after mallocinit(), because it uses runtime_malloc().
	runtime_goargs(argc, (byte **)argv);
	//runtime_goenvs();

	//runtime_memprof_restore();

	// Launch with larger stack to work around initialization issues.
	runtime_grun(mainstart, 0, NULL, 16 * PAGE_SIZE);

	runtime_fibril_teardown();

	// Start scheduling fibrils.
	async_manager();

	// Not reached.
	abort();
}

// Generated by the compiler.
extern void __go_init_main(void);
extern void main_main(void) __asm__ ("main.main");

// The main goroutine.
static void mainstart(void *arg __attribute__((unused)))
{
	// From now on, new goroutines may use non-main threads.
	//runtime_enable_multithread();
	//runtime_create_scavenger();

	__go_init_main();

	// For gccgo we have to wait until after main is initialized
	// to enable GC, because initializing main registers the GC roots.
	runtime_enable_gc();

	// Let scavenger start up.
	runtime_gosched();

	main_main();
	exit(0);
}
